#include "maindialog.h"

#include <QApplication>
#include <QLibraryInfo>
#include <QTextCodec>
#include <QTranslator>
#include <QCommandLineParser>
#include <QtDBus>
#include <QMessageBox>
#include <QDesktopWidget>
#include <signal.h>
#include <unistd.h>
#include "qtsingleapplication/qtsingleapplication.h"
#include "../common/utils.h"
#include "xatom-helper.h"
#include "globalbackupinfo.h"
#include "messageboxutils.h"
#include <ukuistylehelper/ukuistylehelper.h>
#include <windowmanager/windowmanager.h>
#include "backup_manager_interface.h"

// 声明
void initApp(QApplication& a);
bool isManager();
void remountPartitionsForCasperMode();
void centerToScreen(QWidget* widget);

int main(int argc, char *argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif

#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
    QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif

    QtSingleApplication a ("kybackup", argc, argv);
    initApp(a);

    if (a.isRunning()) {
        QString strUid = QString::number(getuid());
        QString ack = a.sendMessage(strUid, 3000);

        if (strUid != ack) {
            MessageBoxUtils::QMESSAGE_BOX_WARNING(nullptr, QObject::tr("Information"),
                                                  QObject::tr("Another user had opened kybackup, you can not start it again."),
                                                  QObject::tr("OK"));
        }

        return EXIT_SUCCESS;
    }

    QString platform = QGuiApplication::platformName();
    if(platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive) || QString(qgetenv("XDG_SESSION_TYPE")) == "wayland") {
        GlobelBackupInfo::instance().setIsWayland(true);
    }
    MainDialog w;
    // 居中窗口
    centerToScreen(&w);
    a.setWindowIcon(QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS, QIcon(":/images/yhkylin-backup-tools.png")));
    a.setActivationWindow(&w, true);
    a.setApplicationName(QObject::tr("Backup & Restore"));
    a.setApplicationVersion("4.1.0.0-0k17.18");

    //如果是第一个实例,则绑定,方便下次调用
    QObject::connect(&a,SIGNAL(messageReceived(const QString&)),&w,SLOT(sltMessageReceived(const QString&)));

    w.show();
    return a.exec();
}

/**
 * @brief 应用初始化
 * @param a
 * @note  new出来的两个QTranslator不用删除，需要整个生命周期内有效，应用结束由操作系统收回即可
 */
void initApp(QApplication& a)
{
    // 前端向后端传递QString参数，若参数中含有中文则保证不会乱码
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

    // 区分中英文
    QString locale = QLocale::system().name();

    // QT自身标准的翻译
#ifndef QT_NO_TRANSLATION
    QTranslator *selfTransOfQt = new QTranslator();
    if (selfTransOfQt->load(QLocale(), QString("qt"), QString("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        a.installTranslator(selfTransOfQt);
    else
        qDebug() << "load qt translator file failed!";
#endif

    // 部分sdk控件用到翻译文件
    QTranslator *transGui = new QTranslator();
    if (locale == "zh_CN") {
        if (transGui->load(":/translations/gui_zh_CN.qm"))
        {
            a.installTranslator(transGui);
        }
    } else if (locale == "bo_CN") {
        if (transGui->load(":/translations/gui_bo_CN.qm"))
        {
            a.installTranslator(transGui);
        }
    } else if (locale == "mn_MN" || locale == "mn") {
        if (transGui->load(":/translations/gui_mn.qm")) {
            a.installTranslator(transGui);
        }
    } else if (locale == "zh_HK") {
        if(transGui->load(":/translations/gui_zh_HK.qm")) {
            a.installTranslator(transGui);
        }
    }

    // 应用内的翻译
    QTranslator *translator = new QTranslator();
    QString translatorResourceName(":/language/qt_");
    translatorResourceName += locale;
    translatorResourceName += ".qm";
    if (!translator->load(translatorResourceName)) //qtcreator启动后看到在资源目录下
        qDebug() << translatorResourceName << "load translator file failed!";
    else {
        a.installTranslator(translator);
        qDebug() << translatorResourceName << "load translator file success!";
    }
//    if (locale == "zh_CN") {
//        //中文需要翻译
//        if (!translator->load(":/language/qt_zh_CN.qm")) //qtcreator启动后看到在资源目录下
//            qDebug() << "load translator file failed!";
//        else
//            a.installTranslator(translator);
//    } else if (locale == "bo_CN") {
//        //藏文需要翻译
//        if (!translator->load(":/language/qt_bo_CN.qm")) //qtcreator启动后看到在资源目录下
//            qDebug() << "load translator file failed!";
//        else
//            a.installTranslator(translator);
//    } else if (locale == "mn_MN") {
//        //蒙古文需要翻译
//        if (!translator->load(":/language/qt_mn_MN.qm")) //qtcreator启动后看到在资源目录下
//            qDebug() << "load translator file failed!";
//        else
//            a.installTranslator(translator);
//    }

    // 命令行参数
    QCommandLineParser parser;
    parser.setApplicationDescription("kybackup helper");
    parser.addHelpOption();
    parser.addVersionOption();
    // 启动后进入的页面
    QCommandLineOption functionOption(QStringList() << "r" << "restore", QCoreApplication::translate("restore", "system restore"));
    parser.addOption(functionOption);
    parser.process(a);
    GlobelBackupInfo::instance().setHasArgRestore(parser.isSet(functionOption));

    Utils::initSysRootPath();
    Utils::initSystemInfo();

    // 初始化日志
    QString logFile = QDir::homePath() + "/.log/kybackup.log";
    logFile.replace("//", "/");
    Utils::setLogFile(logFile);
    qInstallMessageHandler(Utils::customMessageHandler);

    // 当前操作员是否管理员用户
    GlobelBackupInfo::instance().setIsManager(isManager());

    // 试用模式运行时需要将原系统的根分区挂载到/target目录，并将其它分区分别挂载，以备后面系统还原使用
    if (GlobelBackupInfo::instance().isCasper())
    {
        remountPartitionsForCasperMode();
    }
}

/**
 * @brief 判断启动账号是否管理员账号
 * @return true-相当于是；false-不是
 */
bool isManager()
{
    uid_t uid = getuid();
    QString sid = QString::number(uid);
    GlobelBackupInfo::instance().setCurUserId(sid);

    QString rootPath = Utils::getSysRootPath();
    // 只正常启动程序时需校验是否管理员账号启动
    if ("/" != rootPath) {
        // 试用模式运行
        GlobelBackupInfo::instance().setIsCasper(true);
        return true;
    }

    // root用户
    if (0 == uid)
        return true;

    QString userObject = "/org/freedesktop/Accounts/User" + sid;

    // 创建QDBusInterface
    QDBusInterface iface("org.freedesktop.Accounts", userObject, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
    if (!iface.isValid()) {
        qDebug() << qPrintable(QDBusConnection::systemBus().lastError().message());
        exit(1);
    }

    int result = 0;
    QDBusReply<QDBusVariant> reply = iface.call("Get", QString("org.freedesktop.Accounts.User"), QString("AccountType"));
    if (reply.isValid()) {
        QVariant val = reply.value().variant();
        result = val.toInt();
    }

    return 0 == result ? false : true;
}

/**
 * @brief CasperMode重新挂载分区
 * @note 试用模式使用备份还原时需将各个分区挂载到/target目录，当前进入试用模式后，各个分区是挂载到/media/xxx/目录下的，为了方便还原重新挂载到/target目录
 */
void remountPartitionsForCasperMode()
{
    // 卸载/backup分区
    ComKylinBackupManagerInterface intf("com.kylin.backup", "/", QDBusConnection::systemBus());
    intf.remountPartitionsForCasperMode();
}

/**
 * @brief 居中显示窗口
 * @param widget
 */
#include <QScreen>
void centerToScreen(QWidget* widget)
{
    if (!widget)
      return;
    int x = widget->width();
    int y = widget->height();

    if (GlobelBackupInfo::instance().isWayland()){
        // center window
        int sw=QGuiApplication::primaryScreen()->availableGeometry().width();
        int sh=QGuiApplication::primaryScreen()->availableGeometry().height();
        kdk::WindowManager::setGeometry(widget->windowHandle(), QRect((sw - x)/2, (sh - y)/2, x, y));
    } else {
        QDesktopWidget* m = QApplication::desktop();
        // QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos()));
        QRect desk_rect = m->screenGeometry(widget);
        int desk_x = desk_rect.width();
        int desk_y = desk_rect.height();
        widget->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top());
    }
}

